﻿#define MONO_CECIL

#if MONO_CECIL
#else
#define _NET_REFLECTOR
#endif

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Data.EntityClient;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Resources;
using System.Runtime.Remoting.Messaging;
using System.Threading;
using System.Windows.Forms;
using System.Windows.Input;
using CallGraphExtractor;
using Model;
using ModelInitializer;
using Reflector.CodeModel;
using XmlDBAdapter;

namespace Analyzer.ViewModel
{
    public class MainWindowViewModel : ViewModelBase, IDataErrorInfo
    {
        #region Nested Types

        private delegate void CallGraphExtractionSubresultHandler(SubresultEventArgs<CallGraphEdgeCollection> e);
        private delegate void GetAssembliesSubresultHandler(SubresultEventArgs<IAssembly> e);
        private delegate void GetModulesSubresultHandler(SubresultEventArgs<IModule> e);
        private delegate void GetNamespacesSubresultHandler(SubresultEventArgs<string> e);
        private delegate void GetTypesSubresultHandler(SubresultEventArgs<ExtendedType> e);
        private delegate void GetMembersSubresultHandler(SubresultEventArgs<ExtendedMemberReference> e);

        #endregion Nested Types

        #region Fields

        private static readonly string sInitializedModelFileName = "InitializedModel";

        private BackgroundWorker mAnalysisWorker;
        private Extractor mExtractor;
        private CallGraphExtractionSubresultHandler mCallGraphExtractionSubresultHandler;
        private GetAssembliesSubresultHandler mGetAssembliesSubresultHandler;
        private GetModulesSubresultHandler mGetModulesSubresultHandler;
        private GetNamespacesSubresultHandler mGetNamespacesSubresultHandler;
        private GetTypesSubresultHandler mGetTypesSubresultHandler;
        private GetMembersSubresultHandler mGetMembersSubresultHandler;

        private AutoResetEvent mExtractCallGraphModuleNodesAsyncBlocker = new AutoResetEvent(false);
        private AutoResetEvent mExtractCallGraphNamespaceNodesAsyncBlocker = new AutoResetEvent(false);
        private AutoResetEvent mExtractCallGraphTypeNodesAsyncBlocker = new AutoResetEvent(false);
        private AutoResetEvent mExtractCallGraphMemberNodesAsyncBlocker = new AutoResetEvent(false);
        private AutoResetEvent mExtractCallGraphBlocker = new AutoResetEvent(false);

        private HashSet<ExtendedType> mUnresolvedTypes = new HashSet<ExtendedType>();

        #endregion Fields

        #region Lifecycle

        public MainWindowViewModel()
        {
            mExtractor = new Extractor();
            this.Files = new ObservableCollection<AssemblyViewModel>();
            this.IsInitializing = true;
            this.IsInProgress = false;
            this.Progress = 0;
            this.IsProgressIndeterminate = false;
            this.Output = new ObservableCollection<string>();
            this.FxCop10Path =
                new Uri(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles)
                    + "\\Microsoft FxCop 10.0\\FxCopCmd.exe");
            this.FxCopRulesPath = new Uri(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles)
                    + "\\Microsoft FxCop 10.0\\Rules");
            //ISO9126toFxCop_ISO9126.csv
            //ISO9126toFxCop_Mapping.csv

            mExtractor.GetAssembliesSubresultExtracted
                += new EventHandler<SubresultEventArgs<IAssembly>>(mExtractor_GetAssembliesSubresultExtracted);
            mExtractor.GetAssembliesProgressChanged
                += new EventHandler<ProgressChangedEventArgs>(mExtractor_GetAssembliesProgressChanged);
            mExtractor.GetAssembliesDone +=
                new EventHandler<RunWorkerCompletedEventArgs>(mExtractor_GetAssembliesDone);
            mGetAssembliesSubresultHandler = new GetAssembliesSubresultHandler(StoreGetAssembliesSubresult);

            mExtractor.GetModulesSubresultExtracted +=
                new EventHandler<SubresultEventArgs<IModule>>(mExtractor_GetModulesSubresultExtracted);
            mExtractor.GetModulesProgressChanged +=
                new EventHandler<ProgressChangedEventArgs>(mExtractor_GetModulesProgressChanged);
            mExtractor.GetModulesDone +=
                new EventHandler<RunWorkerCompletedEventArgs>(mExtractor_GetModulesDone);
            mGetModulesSubresultHandler = new GetModulesSubresultHandler(StoreGetModulesSubresult);

            mExtractor.GetNamespacesSubresultExtracted +=
                new EventHandler<SubresultEventArgs<string>>(mExtractor_GetNamespacesSubresultExtracted);
            mExtractor.GetNamespacesProgressChanged
                += new EventHandler<ProgressChangedEventArgs>(mExtractor_GetNamespacesProgressChanged);
            mExtractor.GetNamespacesDone
                += new EventHandler<RunWorkerCompletedEventArgs>(mExtractor_GetNamespacesDone);
            mGetNamespacesSubresultHandler = new GetNamespacesSubresultHandler(StoreGetNamespacesSubresult);

            mExtractor.GetTypesSubresultExtracted +=
                new EventHandler<SubresultEventArgs<ExtendedType>>(mExtractor_GetTypesSubresultExtracted);
            mExtractor.GetTypesProgressChanged +=
                new EventHandler<ProgressChangedEventArgs>(mExtractor_GetTypesProgressChanged);
            mExtractor.GetTypesDone +=
                new EventHandler<RunWorkerCompletedEventArgs>(mExtractor_GetTypesDone);
            mGetTypesSubresultHandler = new GetTypesSubresultHandler(StoreGetTypesSubresult);

            mExtractor.GetMembersSubresultExtracted +=
                new EventHandler<SubresultEventArgs<ExtendedMemberReference>>(mExtractor_GetMembersSubresultExtracted);
            mExtractor.GetMembersProgressChanged +=
                new EventHandler<ProgressChangedEventArgs>(mExtractor_GetMembersProgressChanged);
            mExtractor.GetMembersDone +=
                new EventHandler<RunWorkerCompletedEventArgs>(mExtractor_GetMembersDone);
            mGetMembersSubresultHandler = new GetMembersSubresultHandler(StoreGetMembersSubresult);

            mExtractor.ExtractionSubresultExtracted +=
                new EventHandler<SubresultEventArgs<CallGraphEdgeCollection>>(mExtractor_SubresultExtracted);
            mExtractor.ExtractionProgressChanged +=
                new EventHandler<ProgressChangedEventArgs>(mExtractor_ProgressChanged);
            mExtractor.ExtractionDone += new EventHandler<RunWorkerCompletedEventArgs>(mExtractor_ExtractionDone);
            mCallGraphExtractionSubresultHandler =
                new CallGraphExtractionSubresultHandler(StoreCallGraphExtractionSubresult);

            #region DesignTimeData
            if (DesignerProperties.GetIsInDesignMode(new System.Windows.DependencyObject()) == true)
            {
                string codeBase = System.Reflection.Assembly.GetExecutingAssembly().CodeBase;
                UriBuilder uri = new UriBuilder(codeBase);
                string path = Uri.UnescapeDataString(uri.Path);
                string directoryPath = Path.GetDirectoryName(path);

                this.Files.Add(
                    new AssemblyViewModel()
                    {
                        FilePath = directoryPath + "\\executableFile.exe"
                    });
                this.Files.Add(
                    new AssemblyViewModel()
                    {
                        FilePath = directoryPath + "\\libraryFile.dll",
                        IsSelected = true
                    });
                this.Files.Add(
                    new AssemblyViewModel()
                    {
                        FilePath = directoryPath + "\\otherFile.stg"
                    });

                this.IsInProgress = true;
                this.Progress = 50;

                for (int i = 0; i < 5; i++)
                {
                    this.Output.Add("Output" + i.ToString());
                }
            }
            #endregion DesignTimeData
#if DEBUG
            this.CopyCallGraphModel = true;
#endif
        }

        #endregion Lifecycle

        #region Properties

        #region Presentation

        private bool pMustRewriteInitializedModel;
        public bool MustRewriteInitializedModel
        {
            get { return pMustRewriteInitializedModel; }
            set
            {
                if (value != pMustRewriteInitializedModel)
                {
                    pMustRewriteInitializedModel = value;
                    OnPropertyChanged("MustRewriteInitializedModel");
                }
            }
        }

        private string pProjectName;
        public string ProjectName
        {
            get { return pProjectName; }
            set
            {
                if (value.Equals(pProjectName) == false)
                {
                    pProjectName = value;
                    OnPropertyChanged("ProjectName");
                }
            }
        }

        /// <summary>
        /// Gets the collection of files, which will be analyzed.
        /// </summary>
        public ObservableCollection<AssemblyViewModel> Files { get; private set; }

        /// <summary>
        /// Gets a value indicating, that analysis is not yet occured, and the
        /// viewmodel is in a state where parameters should be set.
        /// </summary>
        private bool pIsInitializing;
        public bool IsInitializing
        {
            get { return pIsInitializing; }
            private set
            {
                if (value != pIsInitializing)
                {
                    pIsInitializing = value;
                    OnPropertyChanged("IsInitializing");
                }
            }
        }

        /// <summary>
        /// Gets a value indicating that analysis (or a corresponding activity) is in progress.
        /// </summary>
        private bool pIsInProgress;
        public bool IsInProgress
        {
            get { return pIsInProgress; }
            private set
            {
                if (value != pIsInProgress)
                {
                    pIsInProgress = value;
                    OnPropertyChanged("IsInProgress");
                }
            }
        }

        /// <summary>
        /// Gets, or sets the path to FxCopCmd.exe of FxCop 10.0
        /// </summary>
        private Uri pFxCop10Path;
        public Uri FxCop10Path
        {
            get { return pFxCop10Path; }
            set
            {
                if (value != pFxCop10Path)
                {
                    pFxCop10Path = value;
                    OnPropertyChanged("FxCop10Path");
                }
            }
        }

        /// <summary>
        /// Gets, or sets the path to the folder that contains the FxCop 10.0 rules.
        /// </summary>
        private Uri pFxCopRulesPath;
        public Uri FxCopRulesPath
        {
            get { return pFxCopRulesPath; }
            set
            {
                if (value != pFxCopRulesPath)
                {
                    pFxCopRulesPath = value;
                    OnPropertyChanged("FxCopRulesPath");
                }
            }
        }

        /// <summary>
        /// Gets a value indicating the executability of <see cref="AnalyzeCommand"/>.
        /// </summary>
        public bool CanAnalyze
        {
            get { return this.AnalyzeCommand.CanExecute(null); }
        }

        private int pProgress;
        public int Progress
        {
            get { return pProgress; }
            private set
            {
                if (value != pProgress)
                {
                    pProgress = value;
                    OnPropertyChanged("Progress");
                }
            }
        }

        private bool pIsProgressIndeterminate;
        public bool IsProgressIndeterminate
        {
            get { return pIsProgressIndeterminate; }
            private set
            {
                if (value != pIsProgressIndeterminate)
                {
                    pIsProgressIndeterminate = value;
                    OnPropertyChanged("IsProgressIndeterminate");
                }
            }
        }

        public ObservableCollection<string> Output { get; private set; }

        private bool pHasError;
        public bool HasError
        {
            get { return pHasError; }
            private set
            {
                if (value != pHasError)
                {
                    pHasError = value;
                    OnPropertyChanged("HasError");
                }
            }
        }

        public static string TempDirectoryPath
        {
            get
            {
                return Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)
                    + "\\Analyzer\\temp\\";//System.Reflection.Assembly.GetExecutingAssembly().Location;
                //string dir = Path.GetDirectoryName(path);
            }
        }

        /// <summary>
        /// Gets the path ending with the filename where FxCop will save its output.
        /// </summary>
        public string FxCopOutputPath
        {
            get
            {
                string path = TempDirectoryPath;
                if (Directory.Exists(path) == false)
                    Directory.CreateDirectory(path);

                string value = path
                    + (this.ProjectName.Equals("") == true || this.ProjectName == null
                    ? "noNameProjectAnalysisReport.xml"
                    : this.ProjectName + "AnalysisReport.xml");
                return value;
            }
        }

        #endregion Presentation

        private ActualEntities pContext;
        private ActualEntities Context
        {
            get { return pContext; }
            set
            {
                if (value != pContext)
                    pContext = value;
            }
        }

        private Uri ModelPath { get; set; }

        private bool CopyCallGraphModel { get; set; }

        private static ResourceManager pRM;
        public static ResourceManager RM
        {
            get
            {
                if (pRM == null)
                    pRM = new ResourceManager("Resources", System.Reflection.Assembly.GetExecutingAssembly());
                return pRM;
            }
        }

        #endregion Properties

        #region Commands

        private RelayCommand pAddFilesCommand;
        public ICommand AddFilesCommand
        {
            get
            {
                if (pAddFilesCommand == null)
                    pAddFilesCommand =
                        new RelayCommand(
                            param =>
                            {
                                Microsoft.Win32.OpenFileDialog ofd = new Microsoft.Win32.OpenFileDialog();
                                ofd.AddExtension = true;
                                ofd.DefaultExt = ".ea";
                                ofd.Filter = "Végrehajtható|*.exe|Osztálykönyvtár|*.dll|Minden fájl|*.*";
                                ofd.FilterIndex = 0;
                                ofd.Title = "Fájlok tallózása";
                                ofd.ValidateNames = true;
                                ofd.Multiselect = true;
                                ofd.CheckFileExists = true;
                                ofd.CheckPathExists = true;
                                bool? success = ofd.ShowDialog();
                                if (success.HasValue && success.Value == true)
                                {
                                    foreach (var item in ofd.FileNames)
                                    {
                                        this.Files.Add(
                                            new AssemblyViewModel()
                                            {
                                                FilePath = item,
                                                IsSelected = false
                                            });
                                    }
                                }
                            },
                            param => true);
                return pAddFilesCommand;
            }
        }

        private RelayCommand pRemoveFilesCommand;
        public ICommand RemoveFilesCommand
        {
            get
            {
                if (pRemoveFilesCommand == null)
                    pRemoveFilesCommand =
                        new RelayCommand(
                            param =>
                            {
                                List<AssemblyViewModel> toDelete = new List<AssemblyViewModel>();
                                foreach (var item in this.Files)
                                {
                                    if (item.IsSelected == true)
                                        toDelete.Add(item);
                                }
                                foreach (var item in toDelete)
                                {
                                    this.Files.Remove(item);
                                }
                            },
                            param => this.Files.Count > 0);
                return pRemoveFilesCommand;
            }
        }

        private RelayCommand pAnalyzeCommand;
        public ICommand AnalyzeCommand
        {
            get
            {
                if (pAnalyzeCommand == null)
                    pAnalyzeCommand =
                        new RelayCommand(
                            param =>
                            {
                                mAnalysisWorker = new BackgroundWorker();
                                mAnalysisWorker.WorkerReportsProgress = true;
                                mAnalysisWorker.WorkerSupportsCancellation = true;
                                mAnalysisWorker.DoWork += new DoWorkEventHandler(mAnalysisWorker_DoWork);
                                mAnalysisWorker.ProgressChanged +=
                                    new ProgressChangedEventHandler(mAnalysisWorker_ProgressChanged);
                                mAnalysisWorker.RunWorkerCompleted +=
                                    new RunWorkerCompletedEventHandler(mAnalysisWorker_RunWorkerCompleted);
                                mAnalysisWorker.RunWorkerAsync();
                                this.IsInitializing = false;
                                this.IsInProgress = true;
                            },
                            param => this["FxCop10Path"] == null
                                && this["FxCopRulesPath"] == null
                                && this.IsInitializing == true
                                && this.IsInProgress == false
                                && this.Files.Count > 0);
                return pAnalyzeCommand;
            }
        }

        private RelayCommand pBrowseFxCopCmdCommand;
        public ICommand BrowseFxCopCmdCommand
        {
            get
            {
                if (pBrowseFxCopCmdCommand == null)
                    pBrowseFxCopCmdCommand =
                        new RelayCommand(
                            param =>
                            {
                                Microsoft.Win32.OpenFileDialog ofd = new Microsoft.Win32.OpenFileDialog();
                                ofd.AddExtension = true;
                                ofd.DefaultExt = ".ea";
                                ofd.Filter = "Végrehajtható|*.exe";
                                ofd.FilterIndex = 0;
                                ofd.Title = "FxCopCmd.exe tallózása";
                                ofd.ValidateNames = true;
                                ofd.Multiselect = false;
                                ofd.CheckFileExists = true;
                                ofd.CheckPathExists = true;
                                ofd.InitialDirectory =
                                    Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
                                bool? success = ofd.ShowDialog();
                                if (success.HasValue && success.Value == true)
                                {
                                    foreach (var item in ofd.FileNames)
                                    {
                                        this.Files.Add(
                                            new AssemblyViewModel()
                                            {
                                                FilePath = item,
                                                IsSelected = false
                                            });
                                    }
                                }
                            },
                            param => true);
                return pBrowseFxCopCmdCommand;
            }
        }

        private RelayCommand pBrowseFxCopRulesCommand;
        public ICommand BrowseFxCopRulesCommand
        {
            get
            {
                if (pBrowseFxCopRulesCommand == null)
                    pBrowseFxCopRulesCommand =
                        new RelayCommand(
                            param =>
                            {
                                FolderBrowserDialog fbd = new FolderBrowserDialog();
                                fbd.ShowNewFolderButton = false;
                                fbd.Description = "FxCopCmd.exe tallózása";
                                //fbd.InitialDirectory =
                                //    Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
                                DialogResult result = fbd.ShowDialog();
                                bool? success;
                                switch (result)
                                {
                                    case DialogResult.Cancel:
                                        success = false;
                                        break;
                                    case DialogResult.OK:
                                        success = true;
                                        break;
                                    default:
                                        success = null;
                                        break;
                                }
                                if (success.HasValue && success.Value == true)
                                {
                                    this.FxCopRulesPath = new Uri(fbd.SelectedPath);
                                }
                            },
                            param => true);
                return pBrowseFxCopCmdCommand;
            }
        }

        #endregion Commands

        #region Methods

        /// <summary>
        /// Gets the arguments which will be passed to FxCopCmd.
        /// </summary>
        /// <returns>The arguments</returns>
        public string GetFxCopArguments()
        {
            string value = "/o:\"" + this.FxCopOutputPath + "\" /fo";
            foreach (var item in this.Files)
            {
                value += " /f:\"" + item.FilePath + "\"";
            }
            return value;
        }

        private bool CreateDB()
        {
            DispatchService.Dispatch(() => this.Output.Add("Új adatbázis létrehozása..."));
            this.IsProgressIndeterminate = true;
            string dbPath = null;
            //try
            //{
            string appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\Analyzer";
            if (Directory.Exists(appDataPath) == false)
                Directory.CreateDirectory(appDataPath);
            string newPathTemplate = appDataPath + "\\{0}.db3";
            string initializedModelPath = newPathTemplate.Replace("{0}", sInitializedModelFileName);
            string newModelPath = newPathTemplate.Replace("{0}", this.ProjectName);
            this.IsProgressIndeterminate = false;
            if (File.Exists(newModelPath) == true
                 && (MessageBox.Show(
                        "A fájl " + this.ProjectName + ".db3 már létezik. Felülírjam?",
                        "A fájl már létezik!",
                        MessageBoxButtons.YesNo,
                        MessageBoxIcon.Question) != DialogResult.Yes))
                return false;
            this.IsProgressIndeterminate = true;

            this.ModelPath = new Uri(newModelPath);

            string modelPath = @"Resources\\Model.db3";//RM.GetString("ModelPath");//, CultureInfo.InvariantCulture);
            if (File.Exists(initializedModelPath) == false
                || File.GetLastWriteTime(initializedModelPath) < File.GetLastWriteTime(modelPath)
                || this.MustRewriteInitializedModel == true)
            {
                if (File.GetLastWriteTime(@"..\\..\\Model\\Model\\3rdparty\\Model.db3")
                    > File.GetLastWriteTime(@"Resources\\Model.db3"))
                    throw new InvalidOperationException(@"Resources\\Model.db3" + " is out of date!");//TODO TEST: elvileg ez már nem történhet meg
                File.Copy(modelPath, initializedModelPath, overwrite: true);//TODO: overwrite param

                EntityConnectionStringBuilder builder = new EntityConnectionStringBuilder();
                builder.Metadata = "res://*/ActualModel.csdl|res://*/ActualModel.ssdl|res://*/ActualModel.msl";
                builder.Provider = "System.Data.SQLite";
                builder.ProviderConnectionString = "data source=\"" + initializedModelPath + "\"";
                Initializer init = new Initializer();
                init.ProgressChanged += new EventHandler<ProgressChangedEventArgs>(init_ProgressChanged);
                init.Initialize(new ActualEntities(builder.ConnectionString),
                    Properties.Resources.ISO9126toFxCop_ISO9126,
                    Properties.Resources.ISO9126toFxCop_Mapping,
                    Properties.Resources.ISO9126toFxCop_EffectMatrix,
                    this.FxCopRulesPath);
                init.ProgressChanged -= init_ProgressChanged;
            }
            dbPath = newPathTemplate;
            //}
            //catch (FileNotFoundException ex) { MessageBox.Show(ex.Message); }
            //catch (UnauthorizedAccessException ex) { MessageBox.Show(ex.Message); }
            //catch (ArgumentException ex) { MessageBox.Show(ex.Message); }
            //catch (PathTooLongException ex) { MessageBox.Show(ex.Message); }
            //catch (DirectoryNotFoundException ex) { MessageBox.Show(ex.Message); }
            //catch (IOException ex) { MessageBox.Show(ex.Message); }
            //catch (NotSupportedException ex) { MessageBox.Show(ex.Message); }

            //try
            //{
            File.Copy(initializedModelPath, newModelPath, overwrite: true);
            EntityConnectionStringBuilder builder2 = new EntityConnectionStringBuilder();
            builder2.Metadata = "res://*/ActualModel.csdl|res://*/ActualModel.ssdl|res://*/ActualModel.msl";
            builder2.Provider = "System.Data.SQLite";
            builder2.ProviderConnectionString = "data source=\"" + newModelPath + "\"";
            this.Context = new ActualEntities(builder2.ConnectionString);

            Debug.Assert(this.Context.QualityCharacteristics.Count() > 0);
            Debug.Assert(this.Context.Categories.Count() > 0);
            Debug.Assert(this.Context.Category_Subcharacteristic.Count() > 0);
            Debug.Assert(this.Context.Rules.Count() > 0);
            Debug.Assert(this.Context.Rule_FxCopRule.Count() > 0);
            Debug.Assert(this.Context.Mappings.Count() > 0);
            //}
            //catch (FileNotFoundException ex) { MessageBox.Show(ex.Message); }
            //catch (UnauthorizedAccessException ex) { MessageBox.Show(ex.Message); }
            //catch (ArgumentException ex) { MessageBox.Show(ex.Message); }
            //catch (PathTooLongException ex) { MessageBox.Show(ex.Message); }
            //catch (DirectoryNotFoundException ex) { MessageBox.Show(ex.Message); }
            //catch (IOException ex) { MessageBox.Show(ex.Message); }
            //catch (NotSupportedException ex) { MessageBox.Show(ex.Message); }

            return true;
        }

        /// <summary>
        /// DefaultCollaboration 4.0
        /// </summary>
        private void ExtractCallGraphAssemblyNodesAsync()
        {
            if (this.HasError == true)
                return;
            DispatchService.Dispatch(() => this.Output.Add("Asszemblik meghatározása..."));
            mExtractor.GetAssembliesAsync();
        }

        /// <summary>
        /// DefaultCollaboration 4.1
        /// </summary>
        private void ExtractCallGraphModuleNodesAsync()
        {
            mExtractCallGraphModuleNodesAsyncBlocker.WaitOne();
            if (this.HasError == true)
                return;
            DispatchService.Dispatch(() => this.Output.Add("Modulok meghatározása..."));
            mExtractor.GetModulesAsync();
        }

        /// <summary>
        /// DefaultCollaboration 4.2
        /// </summary>
        private void ExtractCallGraphNamespaceNodesAsync()
        {
            mExtractCallGraphNamespaceNodesAsyncBlocker.WaitOne();
            if (this.HasError == true)
                return;
            DispatchService.Dispatch(() => this.Output.Add("Névterek kinyerése..."));
            mExtractor.GetNamespacesAsync();
        }

        /// <summary>
        /// DefaultCollaboration 4.3
        /// </summary>
        private void ExtractCallGraphTypeNodesAsync()
        {
            mExtractCallGraphTypeNodesAsyncBlocker.WaitOne();
            if (this.HasError == true)
                return;
            DispatchService.Dispatch(() => this.Output.Add("Típusok kinyerése..."));
            mExtractor.GetTypesAsync();
        }

        /// <summary>
        /// DefaultCollaboration 4.4
        /// </summary>
        private void ResolveNestedTypeAssociations()
        {
            ActualEntities context = this.Context;
            lock (context)
                foreach (var item in mUnresolvedTypes)
                {
                    IModule iModule = item.Module;
                    ITypeDeclaration outerTd = null;
                    bool resolved = item.OuterType.TryGetTypeDeclaration(out outerTd);
                    ITypeDeclaration nestedTd = null;
                    resolved &= item.Type.TryGetTypeDeclaration(out nestedTd);
                    if (resolved == true)
                    {
                        Model.Type outerType = context.Types.Where(
                            t => t.Name.Equals(outerTd.Name) && t.NamespaceName.Equals(outerTd.Namespace)
                                   && t.ModuleName.Equals(iModule.Name)
                                   && t.ModuleAssemblyName.Equals(iModule.Assembly.Name)).First();
                        Model.Type nestedType = context.Types.Where(
                            t => t.Name.Equals(nestedTd.Name) && t.NamespaceName.Equals(nestedTd.Namespace)
                                && t.ModuleName.Equals(iModule.Name)
                                && t.ModuleAssemblyName.Equals(iModule.Assembly.Name)).First();

                        nestedType.Outer_TypeName = outerType.Name;
                        nestedType.Outer_TypeNamespaceName = outerType.NamespaceName;
                        nestedType.Outer_TypeModuleName = outerType.ModuleName;
                        nestedType.Outer_TypeModuleAssemblyName = outerType.Outer_TypeModuleAssemblyName;
                        nestedType.OuterType = outerType;
                        outerType.NestedType.Add(nestedType);
                        context.SaveChanges();
                    }
                    else
                        Debugger.Break();
                }
        }

        /// <summary>
        /// DefaultCollaboration 4.5
        /// </summary>
        private void ExtractCallGraphMemberNodesAsync()
        {
            mExtractCallGraphMemberNodesAsyncBlocker.WaitOne();
            if (this.HasError == true)
                return;
            DispatchService.Dispatch(() => this.Output.Add("Tagok kinyerése..."));
            mExtractor.GetMembersAsync();
        }

        /// <summary>
        /// DefaultCollaboration 4.6
        /// </summary>
        private void ExtractCallGraph()
        {
            mExtractCallGraphBlocker.WaitOne();
            if (this.HasError == true)
                return;
            DispatchService.Dispatch(() => this.Output.Add("Hívások kinyerése..."));
            mExtractor.ExtractAsync();
        }

        /// <summary>
        /// DefaultCollaboration 7
        /// </summary>
        private void RunFxCopAnalysis()
        {
            if (this.HasError == true)
                return;

            if (this.CopyCallGraphModel == true)
            {
                File.Copy(this.ModelPath.LocalPath,
                    this.ModelPath.LocalPath.Replace("\\" + this.ProjectName + ".db3",
                        "\\" + this.ProjectName + "_CG.db3"),
                    overwrite: true);
            }

            using (Process p = new Process())
            {
                p.StartInfo.UseShellExecute = false;
                p.StartInfo.RedirectStandardInput = true;
                p.StartInfo.RedirectStandardOutput = true;
                p.StartInfo.RedirectStandardError = true;
                p.StartInfo.CreateNoWindow = true;
                p.StartInfo.FileName = this.FxCop10Path.LocalPath;

                p.StartInfo.Arguments = this.GetFxCopArguments();

                try
                {
                    p.Start();
                    StreamReader reader = p.StandardOutput;
                    StreamWriter writer = p.StandardInput;
                    StreamReader errorReader = p.StandardError;
                    writer.AutoFlush = true;
                    String rawOutput = reader.ReadToEnd();
                    string[] output =
                        rawOutput.Split(new string[] { Environment.NewLine },
                            StringSplitOptions.RemoveEmptyEntries);
                    DispatchService.Dispatch(() =>
                    {
                        foreach (var item in output)
                        {
                            this.Output.Add(item);
                        }
                    });
                    string error = errorReader.ReadToEnd();
                    if (error != null && error.Length != 0)
                        throw new AnalysisException(error);
                }
                catch (Win32Exception ex)
                {
                    System.Windows.MessageBox.Show(ex.Message);
                    this.HasError = true;
                }
            }
        }

        #region Store to DB

        private void StoreGetAssembliesSubresult(SubresultEventArgs<IAssembly> e)
        {
            Debug.WriteLine(e.Subresult.Count.ToString() + " assemblies extracted.");
            Debug.WriteLine("Duplicates:");
            int i = 0;
            lock (this.Context)
            {
                ActualEntities context = this.Context;//new Model.ActualEntities();
                var query = context.Projects.Where(p => p.Name.Equals(this.ProjectName));
                if (query.Count() == 0)
                {
                    context.Projects.AddObject(
                        new Project()
                        {
                            Name = this.ProjectName
                        });
                    context.SaveChanges();
                }
                Debug.WriteLineIf(query.Count() != 1, "Adott nevű projektből nem pontosan 1 található!");
                Project project = query.First();
                foreach (var item in e.Subresult)
                {
                    if (context.Assemblies.Where(a => a.Name.Equals(item.Name)).Count() == 0)
                    {
                        Assembly a =
                            new Assembly()
                            {
                                Name = item.Name,
                                ProjectId = project.Id,
                                Project = project
                            };
                        context.Assemblies.AddObject(a);
                        project.Assemblies.Add(a);
                        context.SaveChanges();
                        i++;
                    }
                    else
                        Debug.Write(item.Name + " ");
                }
            }
            Debug.WriteLine(i.ToString() + " assemblies stored.");
        }

        private void StoreGetModulesSubresult(SubresultEventArgs<IModule> e)
        {
            Debug.WriteLine(e.Subresult.Count.ToString() + " modules extracted.");
            Debug.WriteLine("Duplicates:");
            int i = 0;
            lock (this.Context)
            {
                ActualEntities context = this.Context;//new Model.ActualEntities();
                foreach (var item in e.Subresult)
                {
#if _NET_REFLECTOR
                    string assemblyName =
                        item.Assembly.Name.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)[0];
#elif MONO_CECIL
                    string assemblyName = item.Assembly.Name;
#endif
                    var query = context.Assemblies.Where(
                        a => a.Project.Name.Equals(this.ProjectName) && a.Name.Equals(assemblyName));
                    Debug.WriteLineIf(query.Count() != 1, "Adott nevű projektben adott asszembliből nem pontosan 1 található!");
                    if (context.Modules.Where(
                            m => m.AssemblyName.Equals(assemblyName)
                                && m.Name.Equals(item.Name)).Count() == 0)
                    {
                        Assembly assembly = query.First();
                        Module m =
                            new Module()
                            {
                                Name = item.Name,
                                Assembly = assembly,
                                AssemblyName = assembly.Name
                            };
                        context.Modules.AddObject(m);
                        assembly.Modules.Add(m);
                        context.SaveChanges();
                        i++;
                    }
                    else
                        Debug.Write(item.Name + " ");
                }
            }
            Debug.WriteLine(i.ToString() + " modules stored.");
        }

        private void StoreGetNamespacesSubresult(SubresultEventArgs<string> e)
        {
            Debug.WriteLine(e.Subresult.Count.ToString() + " namespaces extracted.");
            Debug.WriteLine("Duplicates:");
            int i = 0;
            lock (this.Context)
            {
                ActualEntities context = this.Context;//new Model.ActualEntities();
                foreach (var item in e.Subresult)
                {
                    if (context.Namespaces.Where(n => n.Name.Equals(item)).Count() == 0)
                    {
                        context.Namespaces.AddObject(new Namespace() { Name = item });
                        context.SaveChanges();
                        i++;
                    }
                    else
                        Debug.Write(item + " ");
                }
            }
            Debug.WriteLine(i.ToString() + " namespaces stored.");
        }

        private void StoreGetTypesSubresult(SubresultEventArgs<ExtendedType> e)
        {
            Debug.WriteLine(e.Subresult.Count.ToString() + " types extracted.");
            Debug.WriteLine("Duplicates:");
            int i = 0;
            lock (this.Context)
            {
                ActualEntities context = this.Context;//new Model.ActualEntities();
                foreach (var item in e.Subresult)
                {
                    ITypeDeclaration td = null;
                    bool resolved = item.Type.TryGetTypeDeclaration(out td);
                    if (resolved == true)
                    {
                        IModule iModule = item.Module;
                        //var queryA = context.Assemblies.Where(
                        //        a => a.Project.Name.Equals(this.ProjectName) && a.Name.Equals(td.Namespace));
                        //Debug.WriteLineIf(queryA.Count() != 1, "Adott nevű projektben adott asszembliből nem pontosan 1 található!");
                        //Assembly assembly = queryA.First();
                        var queryM = context.Modules.Where(
                            m => m.Name.Equals(iModule.Name)
                                && m.AssemblyName.Equals(iModule.Assembly.Name));
                        Debug.WriteLineIf(queryM.Count() != 1, "Adott modulból nem pontosan 1 található!");
                        Module module = queryM.First();
                        Namespace ns = context.Namespaces.Where(n => n.Name.Equals(td.Namespace)).First();

                        string tdPostfix = GetTypePostfix(td);
                        if (this.Context.Types.Where(
                            p => p.ModuleAssemblyName.Equals(iModule.Assembly.Name)
                                && p.ModuleName.Equals(iModule.Name)
                                && p.NamespaceName.Equals(ns.Name)
                                && p.Name.Equals(td.Name + tdPostfix)).Count() == 0)
                        {
                            Model.Type outerType = null;
                            string outerTdPostfix = "";
                            if (item.OuterType != null)// if item is a nested type
                            {
                                ITypeDeclaration outerTd = null;
                                if (item.OuterType.TryGetTypeDeclaration(out outerTd) == true)
                                {
                                    outerTdPostfix = GetTypePostfix(outerTd);
                                    var queryO = context.Types.Where(
                                        t => t.Name.Equals(outerTd.Name + outerTdPostfix)
                                            && t.NamespaceName.Equals(outerTd.Namespace)
                                            && t.ModuleName.Equals(iModule.Name)
                                            && t.ModuleAssemblyName.Equals(iModule.Assembly.Name));
                                    if (queryO.Count() > 0)// and its outer is already stored in the db
                                        outerType = queryO.First();
                                    else// or if it's not stored, then save it to resolve later, when it's possible
                                        if (mUnresolvedTypes.Contains(item) == false)
                                            mUnresolvedTypes.Add(item);
                                }
                                else
                                    Debugger.Break();
                            }

                            Model.Type type =
                                new Model.Type()
                                {
                                    Module = module,
                                    ModuleAssemblyName = module.AssemblyName,
                                    ModuleName = module.Name,
                                    Name = td.Name + tdPostfix,
                                    Namespace = ns,
                                    NamespaceName = ns.Name,
                                    IsAbstract = td.Abstract,
                                    IsInterface = td.Interface,
                                    IsSealed = td.Sealed,
                                    IsValueType = td.ValueType,
                                    BeforeFieldInit = td.BeforeFieldInit,
                                    RuntimeSpecialName = td.RuntimeSpecialName,
                                    SpecialName = td.SpecialName,
                                    Visibility = td.Visibility.ToString()
                                };
                            if (outerType != null)
                            {
                                type.Outer_TypeName = outerType.Name;
                                type.Outer_TypeNamespaceName = outerType.NamespaceName;
                                type.Outer_TypeModuleName = outerType.Outer_TypeModuleName;
                                type.Outer_TypeModuleAssemblyName = outerType.Outer_TypeModuleAssemblyName;
                                outerType.NestedType.Add(type);
                            }
                            context.Types.AddObject(type);
                            module.Types.Add(type);
                            ns.Types.Add(type);
                            //try
                            //{
                            context.SaveChanges();
                            i++;
                            //}
                            //catch (System.Data.UpdateException ex)
                            //{
                            //    Debug.WriteLine("Store member: " + ex.Message
                            //        + (ex.InnerException != null ? ex.InnerException.Message : ""));
                            //    context.Types.DeleteObject(type);
                            //    module.Types.Remove(type);
                            //    ns.Types.Remove(type);
                            //    context.SaveChanges();
                            //}
                        }
                        else
                            Debug.Write(td.Name + " ");
                    }
                    else
                        Debugger.Break();
                }
#if DEBUG
                var query = this.Context.Types.Where(t => true);
#endif
            }
            Debug.WriteLine(i.ToString() + " types stored.");
        }

        private static string GetTypePostfix(ITypeDeclaration td)
        {
#if _NETREFLECTOR
            return td.GenericArguments.Count == 0
                ? ""
                : "`" + td.GenericArguments.Count.ToString();
#elif MONO_CECIL
            return "";
#endif
        }

        private void StoreGetMembersSubresult(SubresultEventArgs<ExtendedMemberReference> e)
        {
            Debug.WriteLine(e.Subresult.Count.ToString() + " members extracted.");
            Debug.WriteLine("Duplicates:");
            int i = 0;
            lock (this.Context)
            {
                ActualEntities context = this.Context;//new Model.ActualEntities();
                foreach (var item in e.Subresult)
                {
                    IMemberReference mr = item.MemberReference;
                    IModule iModule = item.Module;
                    //var queryA = context.Assemblies.Where(
                    //        a => a.Project.Name.Equals(this.ProjectName) && a.Name.Equals(td.Namespace));
                    //Debug.WriteLineIf(queryA.Count() != 1, "Adott nevű projektben adott asszembliből nem pontosan 1 található!");
                    //Assembly assembly = queryA.First();
                    var queryM = context.Modules.Where(
                        m => m.Name.Equals(iModule.Name) && m.AssemblyName.Equals(iModule.Assembly.Name));
                    Debug.WriteLineIf(queryM.Count() != 1, "Adott modulból nem pontosan 1 található!");
                    Module module = queryM.First();
                    ITypeDeclaration declaringType = null;
                    if (mr.DeclaringType.TryGetTypeDeclaration(out declaringType) == true)
                    {
                        string memberName = mr.ToString();
                        string declaringTypePostfix = GetTypePostfix(declaringType);
                        if (this.Context.Members.Where(
                            mem => mem.TypeModuleAssemblyName.Equals(iModule.Assembly.Name)
                                && mem.TypeModuleName.Equals(item.Module.Name)
                                && mem.TypeName.Equals(declaringType.Name + declaringTypePostfix)
                                && mem.TypeNamespaceName.Equals(declaringType.Namespace)
                                && mem.Name.Equals(memberName)).Count() == 0)
                        {
                            Model.Type type = context.Types.Where(
                                t => t.Name.Equals(declaringType.Name + declaringTypePostfix)
                                    && t.ModuleName.Equals(item.Module.Name)
                                    && t.NamespaceName.Equals(declaringType.Namespace)
                                    && t.ModuleAssemblyName.Equals(iModule.Assembly.Name)).First();

                            Member member =
                                new Member()
                                {
                                    Name = memberName,
                                    Type = type,
                                    TypeName = type.Name,
                                    TypeNamespaceName = type.NamespaceName,
                                    TypeModuleName = type.ModuleName,
                                    TypeModuleAssemblyName = type.ModuleAssemblyName,
                                    MemberKind = mr.GetMemberKind().ToString()
                                };

                            context.Members.AddObject(member);
                            type.Members.Add(member);
                            //try
                            //{
                            context.SaveChanges();
                            i++;
                            //}
                            //catch (System.Data.UpdateException ex)
                            //{
                            //    Debug.WriteLine("Store member: " + ex.Message
                            //        + (ex.InnerException != null ? ex.InnerException.Message : ""));
                            //    context.Members.DeleteObject(member);
                            //    type.Members.Remove(member);
                            //    context.SaveChanges();
                            //}
                        }
                        else
                            Debug.Write(memberName + " ");
                    }
                    else
                        Debugger.Break();
                }
#if DEBUG
                var query = this.Context.Members.Where(m => true);
#endif
            }
            Debug.WriteLine(i.ToString() + " members stored.");
        }

        private void StoreCallGraphExtractionSubresult(SubresultEventArgs<CallGraphEdgeCollection> e)
        {
            Debug.WriteLine(e.Subresult.Count.ToString() + " callgraph edges extracted.");
            int i = 0;
            lock (this.Context)
            {
                ActualEntities context = this.Context;//new Model.ActualEntities();
                foreach (var item in e.Subresult)
                {
                    // Store needed information in locals
                    IMemberReference caller = item.Caller.MemberReference;
                    string callerMemberName = caller.ToString();
                    ITypeDeclaration callerTypeDeclaration = null;
                    if (caller.DeclaringType.TryGetTypeDeclaration(out callerTypeDeclaration) == true)
                    {
                        if (callerTypeDeclaration == null)
                            Debugger.Break();
                        string callerTypeName =
                            callerTypeDeclaration.Name + GetTypePostfix(callerTypeDeclaration);
                        string callerNamespaceName = callerTypeDeclaration.Namespace;
                        string callerModuleName = item.Caller.Module.Name;
                        string callerAssemblyName = item.Caller.Module.Assembly.Name;
                        // Find caller entities
                        var query = context.Members.Where(
                                m =>
                                    m.Name.Equals(callerMemberName)
                                    && m.TypeName.Equals(callerTypeName)
                                    && m.TypeNamespaceName.Equals(callerNamespaceName)
                                    && m.TypeModuleName.Equals(callerModuleName)
                                    && m.TypeModuleAssemblyName.Equals(callerAssemblyName)
                                    );
                        Debug.Assert(query.Count() == 1, "Pontosan egy entitás kellene létezzen az adott értékekkel!");
                        Member callerMember = query.First();
                        Model.Type callerType = callerMember.Type;
                        Namespace callerNamespace = callerType.Namespace;
                        Module callerModule = callerType.Module;
                        Model.Assembly callerAssembly = callerModule.Assembly;

                        foreach (var callGraphEdge in item.Called)
                        {
                            StoreCallGraphEdge(context, callerMemberName, callerTypeName, callerNamespaceName,
                                callerModuleName, callerAssemblyName, callGraphEdge);
                            i++;
                        }
                    }
                    else
                        Debugger.Break();
                }
            }
            Debug.WriteLine(i.ToString() + " callgraph edges stored.");
        }

        private static void StoreCallGraphEdge(ActualEntities context, string callerMemberName,
            string callerTypeName, string callerNamespaceName, string callerModuleName,
            string callerAssemblyName, CallGraphExtractor.CallGraphEdge callGraphEdge)
        {
            // Store needed information in locals
            IMemberReference callee = callGraphEdge.ExtendedMemberReference.MemberReference;
            string calleeMemberName = callee.ToString();
            ITypeDeclaration calleeTypeDeclaration = null;
            if (callee.DeclaringType.TryGetTypeDeclaration(out calleeTypeDeclaration) == true)
            {
                string calleeTypeName = calleeTypeDeclaration.Name + GetTypePostfix(calleeTypeDeclaration);
                string calleeNamespaceName = calleeTypeDeclaration.Namespace;
                string calleeModuleName = callGraphEdge.ExtendedMemberReference.Module.Name;
                string calleeAssemblyName = callGraphEdge.ExtendedMemberReference.Module.Assembly.Name;
                string callTypeS = callGraphEdge.CallType.ToString();
                // Find callee entities
                var query = context.Members.Where(
                        m =>
                            m.Name.Equals(calleeMemberName)
                            && m.TypeName.Equals(calleeTypeName)
                            && m.TypeNamespaceName.Equals(calleeNamespaceName)
                            && m.TypeModuleName.Equals(calleeModuleName)
                            && m.TypeModuleAssemblyName.Equals(calleeAssemblyName)
                            );
                Member calleeMember = query.First();
                Model.Type calleeType = calleeMember.Type;
                Namespace calleeNamespace = calleeType.Namespace;
                Module calleeModule = calleeType.Module;
                Model.Assembly calleeAssembly = calleeModule.Assembly;

                // Adding new entities
                if (callerAssemblyName.Equals(calleeAssemblyName) == false)
                    context.CallGraphEdge_AssemblyDependency.AddObjectSafe(
                        new Model.CallGraphEdge_AssemblyDependency()
                        {
                            Caller_AssemblyName = callerAssemblyName,
                            Callee_AssemblyName = calleeAssemblyName
                        },
                        callTypeS);
                if (callerModuleName.Equals(calleeModule) == false
                    && callerAssemblyName.Equals(calleeAssemblyName) == false)
                    context.CallGraphEdge_ModuleDependency.AddObjectSafe(
                        new Model.CallGraphEdge_ModuleDependency()
                        {
                            Caller_ModuleAssemblyName = callerAssemblyName,
                            Callee_ModuleAssemblyName = calleeAssemblyName,
                            Caller_ModuleName = callerModuleName,
                            Callee_ModuleName = calleeModuleName
                        },
                        callTypeS);
                if (callerNamespaceName.Equals(calleeNamespace) == false)
                    context.CallGraphEdge_NamespaceDependency.AddObjectSafe(
                        new Model.CallGraphEdge_NamespaceDependency()
                        {
                            Caller_NamespaceName = callerNamespaceName,
                            Callee_NamespaceName = calleeNamespaceName
                        },
                        callTypeS);
                if (callerTypeName.Equals(calleeTypeName) == false
                    && callerNamespaceName.Equals(calleeNamespace) == false
                    && callerModuleName.Equals(calleeModule) == false
                    && callerAssemblyName.Equals(calleeAssemblyName) == false)
                    context.CallGraphEdge_TypeDependency.AddObjectSafe(
                        new Model.CallGraphEdge_TypeDependency()
                        {
                            Caller_TypeModuleAssemblyName = callerAssemblyName,
                            Callee_TypeModuleAssemblyName = calleeAssemblyName,
                            Caller_TypeModuleName = callerModuleName,
                            Callee_TypeModuleName = calleeModuleName,
                            Caller_TypeNamespaceName = callerNamespaceName,
                            Callee_TypeNamespaceName = calleeNamespaceName,
                            Caller_TypeName = callerTypeName,
                            Callee_TypeName = calleeTypeName
                        },
                        callTypeS);
                context.CallGraphEdge_MemberDependency.AddObjectSafe(
                    new Model.CallGraphEdge_MemberDependency()
                    {
                        Caller_MemberTypeModuleAssemblyName = callerAssemblyName,
                        Callee_MemberTypeModuleAssemblyName = calleeAssemblyName,
                        Caller_MemberTypeModuleName = callerModuleName,
                        Callee_MemberTypeModuleName = calleeModuleName,
                        Caller_MemberTypeNamespaceName = callerNamespaceName,
                        Callee_MemberTypeNamespaceName = calleeNamespaceName,
                        Caller_MemberTypeName = callerTypeName,
                        Callee_MemberTypeName = calleeTypeName,
                        Caller_MemberName = callerMemberName,
                        Callee_MemberName = calleeMemberName
                    },
                    callTypeS);
            }
            else
                Debugger.Break();
        }

        #endregion Store to DB

        #endregion Methods

        #region EventHandlers

        void HandlerProgressChanged(ProgressChangedEventArgs e)
        {
            if (e.ProgressPercentage < 0)
            {
                this.IsProgressIndeterminate = true;
                this.Progress = 0;
            }
            else
            {
                this.IsProgressIndeterminate = false;
                this.Progress = e.ProgressPercentage;
            }
        }

        #region init

        void init_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            HandlerProgressChanged(e);
            string message = e.UserState as string;
            if (message != null)
                DispatchService.Dispatch(() => this.Output.Add(message));
        }

        #endregion init

        #region mAnalysisWorker

        /// <summary>
        /// DefaultCollaboration 4
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void mAnalysisWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            if (CreateDB() == false)
            {
                this.HasError = true;
                return;
            }
            this.IsProgressIndeterminate = false;

            mExtractor.AssemblyPaths.Clear();
            foreach (var file in this.Files)
            {
                try
                {
                    mExtractor.AssemblyPaths.Add(new Uri(file.FilePath, UriKind.Absolute));
                }
                catch (UriFormatException ex)
                {
                    System.Windows.MessageBox.Show(ex.Message);
                    this.HasError = true;
                    return;
                }
            }
            ExtractCallGraphAssemblyNodesAsync();
        }

        void mAnalysisWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            throw new NotImplementedException();
        }

        void mAnalysisWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                this.HasError = true;
                System.Windows.MessageBox.Show(e.Error.Message);
            }
        }

        #endregion mAnalysisWorker

        #region mCallGraphExtractor

        #region Assemblies

        void mExtractor_GetAssembliesSubresultExtracted(object sender, SubresultEventArgs<IAssembly> e)
        {
            mGetAssembliesSubresultHandler.BeginInvoke(
                e,
                new AsyncCallback(mGetAssembliesSubresultHandler_CallbackMethod),
                null);
        }

        void mGetAssembliesSubresultHandler_CallbackMethod(IAsyncResult result)
        {
            GetAssembliesSubresultHandler caller =
                (GetAssembliesSubresultHandler)((AsyncResult)result).AsyncDelegate;
            caller.EndInvoke(result);
            if (mGetAssembliesDone == true)
                mExtractCallGraphModuleNodesAsyncBlocker.Set();
        }

        void mExtractor_GetAssembliesProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            HandlerProgressChanged(e);
        }

        private bool mGetAssembliesDone = false;
        void mExtractor_GetAssembliesDone(object sender, RunWorkerCompletedEventArgs e)
        {
            mGetAssembliesDone = true;
            if (e.Error != null || e.Cancelled == true)
            {
                this.HasError = true;
                return;
            }
            DispatchService.Dispatch(() => this.Output.Add("...kész."));
            ExtractCallGraphModuleNodesAsync();
        }

        #endregion Assemblies

        #region Modules

        void mExtractor_GetModulesSubresultExtracted(object sender, SubresultEventArgs<IModule> e)
        {
            mGetModulesSubresultHandler.BeginInvoke(
                e,
                new AsyncCallback(mGetModulesSubresultHandler_CallbackMethod),
                null);
        }

        void mGetModulesSubresultHandler_CallbackMethod(IAsyncResult result)
        {
            GetModulesSubresultHandler caller =
                (GetModulesSubresultHandler)((AsyncResult)result).AsyncDelegate;
            caller.EndInvoke(result);
            if (mGetModulesDone == true)
                mExtractCallGraphNamespaceNodesAsyncBlocker.Set();
        }

        void mExtractor_GetModulesProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            HandlerProgressChanged(e);
        }

        private bool mGetModulesDone = false;
        void mExtractor_GetModulesDone(object sender, RunWorkerCompletedEventArgs e)
        {
            mGetModulesDone = true;
            if (e.Error != null || e.Cancelled == true)
            {
                this.HasError = true;
                return;
            }
            DispatchService.Dispatch(() => this.Output.Add("Modulok kinyerése kész!"));
            ExtractCallGraphNamespaceNodesAsync();
        }

        #endregion Modules

        #region Namespaces

        void mExtractor_GetNamespacesSubresultExtracted(object sender, SubresultEventArgs<string> e)
        {
            mGetNamespacesSubresultHandler.BeginInvoke(
                e,
                new AsyncCallback(mGetNamespacesSubresultHandler_CallbackMethod),
                null);
        }

        void mGetNamespacesSubresultHandler_CallbackMethod(IAsyncResult result)
        {
            GetNamespacesSubresultHandler caller =
                (GetNamespacesSubresultHandler)((AsyncResult)result).AsyncDelegate;
            caller.EndInvoke(result);
            if (mGetNamespacesDone == true)
                mExtractCallGraphTypeNodesAsyncBlocker.Set();
        }

        void mExtractor_GetNamespacesProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            HandlerProgressChanged(e);
        }

        private bool mGetNamespacesDone = false;
        void mExtractor_GetNamespacesDone(object sender, RunWorkerCompletedEventArgs e)
        {
            mGetNamespacesDone = true;
            if (e.Error != null || e.Cancelled == true)
            {
                this.HasError = true;
                return;
            }
            DispatchService.Dispatch(() => this.Output.Add("Névterek kinyerése kész!"));
            ExtractCallGraphTypeNodesAsync();
        }

        #endregion Namespaces

        #region Types

        void mExtractor_GetTypesSubresultExtracted(object sender, SubresultEventArgs<ExtendedType> e)
        {
            mGetTypesSubresultHandler.BeginInvoke(
                e,
                new AsyncCallback(mGetTypesSubresultHandler_CallbackMethod),
                null);
        }

        void mGetTypesSubresultHandler_CallbackMethod(IAsyncResult result)
        {
            GetTypesSubresultHandler caller =
                (GetTypesSubresultHandler)((AsyncResult)result).AsyncDelegate;
            caller.EndInvoke(result);
            if (mGetTypesDone == true)
                mExtractCallGraphMemberNodesAsyncBlocker.Set();
        }

        void mExtractor_GetTypesProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            HandlerProgressChanged(e);
        }

        private bool mGetTypesDone = false;
        void mExtractor_GetTypesDone(object sender, RunWorkerCompletedEventArgs e)
        {
            mGetTypesDone = true;
            if (e.Error != null || e.Cancelled == true)
            {
                this.HasError = true;
                return;
            }
            DispatchService.Dispatch(() => this.Output.Add("Hiányzó Type-NestedType asszociációk létrehozása kész!"));
            ResolveNestedTypeAssociations();
            DispatchService.Dispatch(() => this.Output.Add("Típusok kinyerése kész!"));
            ExtractCallGraphMemberNodesAsync();
        }

        #endregion Types

        #region Members

        void mExtractor_GetMembersSubresultExtracted(object sender, SubresultEventArgs<ExtendedMemberReference> e)
        {
            mGetMembersSubresultHandler.BeginInvoke(
                e,
                new AsyncCallback(mGetMembersSubresultHandler_CallbackMethod),
                null);
        }

        void mGetMembersSubresultHandler_CallbackMethod(IAsyncResult result)
        {
            GetMembersSubresultHandler caller =
                (GetMembersSubresultHandler)((AsyncResult)result).AsyncDelegate;
            caller.EndInvoke(result);
            if (mGetMembersDone == true)
                mExtractCallGraphBlocker.Set();
        }

        void mExtractor_GetMembersProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            HandlerProgressChanged(e);
        }

        private bool mGetMembersDone = false;
        void mExtractor_GetMembersDone(object sender, RunWorkerCompletedEventArgs e)
        {
            mGetMembersDone = true;
            if (e.Error != null || e.Cancelled == true)
            {
                this.HasError = true;
                return;
            }
            DispatchService.Dispatch(() => this.Output.Add("Tagok kinyerése kész!"));
            ExtractCallGraph();
        }

        #endregion Members

        #region Calls

        void mExtractor_SubresultExtracted(object sender, SubresultEventArgs<CallGraphEdgeCollection> e)
        {
            mCallGraphExtractionSubresultHandler.BeginInvoke(
                e,
                new AsyncCallback(mCallGraphExtractionSubresultHandler_CallbackMethod),
                null);
        }

        void mCallGraphExtractionSubresultHandler_CallbackMethod(IAsyncResult result)
        {
            CallGraphExtractionSubresultHandler caller =
                (CallGraphExtractionSubresultHandler)((AsyncResult)result).AsyncDelegate;
            caller.EndInvoke(result);
        }

        void mExtractor_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            HandlerProgressChanged(e);
        }

        void mExtractor_ExtractionDone(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null || e.Cancelled == true)
            {
                this.HasError = true;
                return;
            }
            DispatchService.Dispatch(() => this.Output.Add("Hívási gráf kinyerése kész!"));
            RunFxCopAnalysis();
            try
            {
                using (ActualEntities context = new ActualEntities(this.Context.Connection.ConnectionString))
                {
                    new Adapter().ParseToDB(this.FxCopOutputPath, context);
                }
            }
            catch (FileNotFoundException ex)
            {
                this.HasError = true;
                DispatchService.Dispatch(() => this.Output.Add(ex.Message));
                return;
            }
            DispatchService.Dispatch(() => this.Output.Add("FxCop analízis eredményének feldolgozása kész!"));

            MessageBox.Show("!");
            this.IsProgressIndeterminate = false;
            this.Progress = 0;
        }

        #endregion Calls

        #endregion mCallGraphExtractor

        #endregion EventHandlers

        #region IDataErrorInfo Members

        public string Error
        {
            get { throw new NotImplementedException(); }
        }

        public string this[string property]
        {
            get
            {
                string msg = null;
                switch (property)
                {
                    case "FxCop10Path":
                        if (File.Exists(this.FxCop10Path.LocalPath) == false)
                            msg = "A " + this.FxCop10Path.AbsolutePath
                                + " fájl nem található! Használja a Tallózás funkciót!";
                        break;
                    case "FxCopRulesPath":
                        if (Directory.Exists(this.FxCopRulesPath.LocalPath) == false)
                            msg = "A " + this.FxCopRulesPath
                                + " mappa nem található! Használja a Tallózás funkciót!";
                        break;
                    default:
                        throw new ArgumentException(
                            "Unrecognized property: " + property);
                }
                return msg;
            }
        }

        #endregion
    }
}
